package com.lin.controller;

import cn.hutool.json.ObjectMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.lin.dto.UserFormDTO;
import com.lin.po.UserPO;
import com.lin.query.UserQuery;
import com.lin.service.UserService;
import com.lin.vo.AddressVO;
import com.lin.vo.UserVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

import cn.hutool.core.bean.BeanUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 使用路径参数时, 需要使用@PathVariable注解, 并且需要指定参数名<br>
 * 若不指定路径参数名, 则抛出IllegalArgumentException<br>
 * <code>如: @PathVariable("id") Integer id</code>
 */
@Api(value = "用户管理接口", tags = {"用户接口"})
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    /** userService.save()需要传入一个User对象,
     * 而UserFormDTO和User的字段类似, 所以需要转换一下
     * <p>springframework下的BeanUtils类, 这种方式需要提前创建目标对象, 作为第二个参数</p>
     * <code>public static void copyProperties(Object source, Object target)</code>
     * <p>hutool工具类下的BeanUtil类, 这种方式第二个参数需要的是目标对象的字节码文件</p>
     * <code>public static <T> T copyProperties(Object source, Class<T> tClass, String... ignoreProperties)</code><br>
     * 注意方法返回值是void, 所以不能直接返回User对象,
     * 需要返回一个UserVO对象
     */
    @ApiOperation(value = "新增用户接口")
    @PostMapping
    public void saveUser(@ApiParam(value = "用户信息") @RequestBody UserFormDTO userDTO) {
        // 通过hutool工具包提供的方法转换
        UserPO userPO = BeanUtil.copyProperties(userDTO, UserPO.class);
        // 调用service层新增用户方法
        userService.save(userPO);
    }


    @ApiOperation(value = "删除用户接口")
    @DeleteMapping("/{id}")
    public void removeUser(@ApiParam(value = "用户ID") @PathVariable("id") Long id) {
        userService.removeById(id);
    }

    @ApiOperation(value = "根据id查询用户接口")
    @GetMapping("{id}")
    public UserVO queryUserById(@ApiParam(value = "用户ID") @PathVariable("id") Long id) {
        // 查询用户PO      Persistent Object
        UserPO userPo = userService.getById(id);
        // 返回UserVO     View Object
        return BeanUtil.copyProperties(userPo, UserVO.class);
    }

    @ApiOperation(value = "根据id查询用户信息并返回对应地址接口")
    @GetMapping(value = "{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public UserVO queryUserAndAddrById(@ApiParam(value = "用户ID") @PathVariable("id") Long id) {
        return userService.getUserAndAddrById(id);
    }

    @ApiOperation(value = "根据id批量查询用户接口")
    @GetMapping("/single")
    public List<UserVO> queryUsersByIds(@ApiParam(value = "用户ID") @RequestParam("ids") List<Long> ids) {
        // 查询用户PO      Persistent Object
        List<UserPO> userPOS = userService.listByIds(ids); // IService封装好的方法
        // 返回UserVO     View Object
        return BeanUtil.copyToList(userPOS, UserVO.class); // hutool工具包封装的转换类型
    }

    @ApiOperation(value = "根据id批量查询用户接口")
    @GetMapping("/multiple")
    public List<UserVO> queryUsersAndAddrByIds(@ApiParam(value = "用户ID") @RequestParam("ids") List<Long> ids) {
        return userService.getUsersAndAddrByIds(ids);
    }

    @ApiOperation(value = "根据id扣减用户余额接口")
    @PutMapping("/{id}/deduction/{minBalance}")
    public void deductBalanceById(@ApiParam(value = "用户ID") @PathVariable("id") Integer id,
                                  @ApiParam(value = "扣减金额") @PathVariable("minBalance") Integer minBalance) {
        /*
        这种方式可以实现操作, 但是sql不应该出现在service层, 应该交给持久层处理
        LambdaUpdateWrapper<UserPO> updateWrapper = new LambdaUpdateWrapper<UserPO>()
                .eq(UserPO::getId, id)
                .ge(UserPO::getBalance, minBalance)
                .setSql("balance = balance - " + minBalance);
        userService.update(updateWrapper);*/
        userService.deductBalanceById(id, minBalance);
    }

    /**
     * 这里条件比较多, 不建议一个一个用RequestParam获取, 建议封装到一个对象中, 这里接收这个对象即可
     * @return 符合条件的用户信息
     */
    @ApiOperation(value = "根据条件查询用户信息接口")
    @GetMapping("/condition")
    public List<UserVO> deductBalanceByCondition(UserQuery userQuery) {
        List<UserPO> userPOS = userService.queryByCondition(
                userQuery.getName(), userQuery.getStatus(),
                userQuery.getMinBalance(), userQuery.getMaxBalance());
        return BeanUtil.copyToList(userPOS, UserVO.class);
    }

    @ApiOperation(value = "根据条件更新用户信息接口")
    @PutMapping("/condition/{id}/{money}")
    public void updateByCondition(@ApiParam(value = "用户ID") @PathVariable("id") Integer id,
                                    @ApiParam(value = "更新金额") @PathVariable("money") Integer money
    ) {
        userService.updateByCondition(id, money);
    }

    @ApiOperation(value = "根据用户id查询用户收货地址接口")
    @GetMapping("/addr/{id}")
    public List<AddressVO> queryAddrByUserId(@ApiParam(value = "用户ID") @PathVariable("id") Long id) {
        return userService.queryAddrByUserId(id);
    }

}
